package sennetwork;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Observable;
import java.util.Observer;
import java.util.concurrent.ArrayBlockingQueue;

import sennetworkserver.Lane;
import sennetworkserver.LaneStore;
import sennetworkserver.Sensor;

public class NetworkClient implements Runnable, Observer {
	
	static final int BUFFER_SIZE = 64 * 64;
	
	private Socket clientSocket;
	private int port;
	private Thread clientThread;
	private String address;
	private InputStream reader;
	private OutputStream writer;
	private ArrayBlockingQueue<SensorMessage> queue;
	
	public LaneStore laneStore;
	
	public NetworkClient(String address, int port) {
		this.address = address;
		this.port = port;
		this.queue = new ArrayBlockingQueue<SensorMessage>(BUFFER_SIZE);
		
		for(Lane lane : LaneStore.getAllLanes()) {
			lane.getSensor100m().addObserver(this);
			lane.getSensor1m().addObserver(this);
		}
		
		clientThread = new Thread(this, "NetworkClient");
		clientThread.start();
	}

	@Override
	public void run() {
		try {
			clientSocket = new Socket(address, port);
			reader = clientSocket.getInputStream();
			writer = clientSocket.getOutputStream();
			
			if (clientSocket.isConnected())
				System.out.println("Connected");
			
			while(clientSocket.isConnected()){
				while(!queue.isEmpty()) {
					SensorMessage message = queue.take();
					writer.write(message.toByte());
				}
				
				if (reader.available() >= 2) {
					Lane lane = LaneStore.getLane(reader.read());
					int stateByte = reader.read();
					if(lane != null) {
						lane.getTrafficLight().setState(stateByte);
						lane.getTrafficLight().notifyObservers();			
					}
				}
				
				Thread.sleep(50);
			}						
		} catch (UnknownHostException e) {
			System.out.println(e.getMessage());
		} catch (IOException e) {
			System.out.println(e.getMessage());
		} catch (InterruptedException e) {
			System.out.println(e.getMessage());
		}
	}

	@Override
	public void update(Observable o, Object obj) {
		try {
			Lane lane = LaneStore.getLane(((Sensor) o).getLaneId());
			int sensorId = 0;
			if(lane.getSensor100m() == ((Sensor) o)) {
				sensorId = 1;
			} else if(lane.getSensor1m() == ((Sensor) o)) {
				sensorId = 2;
			} else {
				throw new Exception("Not a valid Sensor");
			}
			
			SensorMessage message = new SensorMessage(lane.getLaneId(), sensorId);
			
			if (queue.size() < BUFFER_SIZE)
				queue.put(message);
			else
				System.err.println("Dropped a message");
			
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}
}
